<template>
  <q-input ref="QNumber" v-model.number="number" :disable="disable" :lazy-rules="lazyRule" :placeholder="placeTips"
           :readonly="readonly" :rules="nRules" step="any" title type="number" v-bind="$attrs" @blur="handleBlur"
           @update:model-value="updateNumber">
    <template v-for="item in Object.keys(useSlots())" v-slot:[item]>
      <slot :name="item"></slot>
    </template>
  </q-input>
</template>

<script setup>
import { computed, nextTick, ref, useSlots, watch } from 'vue'
import { isEmpty } from 'src/utils/utils'
import { i18n } from 'boot/i18n'

const props = defineProps({
  rules: Array,
  blur: Function,
  input: Function,
  disable: Boolean,
  readonly: Boolean,
  placeholder: String,
  min: [String, Number],
  max: [String, Number],
  decimals: [String, Number],
  lazyRules: [Boolean, String],
  modelValue: [String, Number]
})

const emits = defineEmits(['update:modelValue', 'blur', 'input'])

const number = ref(null)
const QNumber = ref(null)
const isUpdate = ref(false)
const lazyRule = computed(() => {
  if (props.lazyRules === true) return false
  return props.lazyRules
})

const placeTips = computed(() => {
  if (isEmpty(props.min) && isEmpty(props.max) && isEmpty(props.decimals)) return props.placeholder
  let str = i18n.t('PleaseInput')
  if (!isEmpty(props.min) && !isEmpty(props.max)) str += i18n.t('NumTips', [props.min, props.max])
  else if (isEmpty(props.min) && !isEmpty(props.max)) str += i18n.t('LessThanTips', [props.max])
  else if (!isEmpty(props.min) && isEmpty(props.max)) str += i18n.t('GreaterThanTips', [props.min])
  else str = props.placeholder
  if (!isEmpty(props.decimals)) {
    if ([0, '0'].includes(props.decimals)) str += `(${i18n.t('IntegerOnlySupport')})`
    else str += `(${i18n.t('DecimalDigits', [props.decimals])})`
  }
  return str
})
const REG = computed(() => {
  if (!(props.decimals >= 0)) return void 0
  if ([0, '0'].includes(props.decimals)) return /^-?\d+$/
  return new RegExp(new RegExp('\\.\\d{0,' + props.decimals + '}/?$'))
})
const nRules = computed(() => {
  const { readonly, disable } = props
  if (readonly || disable) return []
  const rules = props.rules || []
  if (!isEmpty(props.min)) rules.push(val => (isEmpty(val) || val >= props.min) || i18n.t('NotLess', [props.min]))
  if (!isEmpty(props.max)) rules.push(val => (isEmpty(val) || val <= props.max) || i18n.t('NotGreater', [props.max]))
  if (REG.value) {
    rules.push(val => (isEmpty(val) || /^-?\d+$/.test(val) || REG.value.test(val)) ||
      i18n.t('DecimalDigits', [props.decimals]))
  }
  return rules
})

const initValue = () => {
  if (props.modelValue !== number.value) {
    number.value = props.modelValue
    nextTick(() => QNumber.value && QNumber.value.resetValidation())
  }
}
const updateNumber = (e = '') => {
  isUpdate.value = true
  emits('update:modelValue', e)
}
const handleBlur = () => {
  const { blur, input } = props
  if (blur && typeof blur === 'function') blur(number.value)
  else emits('blur', number.value)
  if (!isUpdate.value) return
  isUpdate.value = false
  if (input && typeof input === 'function') props.input(number.value)
  else emits('input', number.value)
}
watch(() => props.modelValue, () => initValue(), { immediate: true })
</script>